using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using BuildingBasicDomain;
using CommonTypes;
using MVCFramework;



namespace BuildingStructuralElements
{
    [Serializable]
    public class ElasticLine : Line, IModelData
    {
        public System.Drawing.Color Color;
    }

    public interface INodeLine : IContainer<Node>, ILine
    {
        INodeLine[] SplitLineToNodes();
        INodeLine[] SplitLine(int number);
      //  ILine[] Segments
    }

    [ModelContainment(true)] 
    [Serializable ]
    public class NodeLine : Line, IContainer<Node>, IModifiable, INodeLine
    {
        # region " private Decleration  "

        private IList<Node> nodeList;

        [ModelContainment]
        public IList<Node> NodeList
        {
            get
            {
                if (nodeList == null)
                    nodeList = new   DomainCollection<Node>();
                return nodeList;
            }
            set { nodeList = value; }
        }

        #endregion

        public INodeLine[] SplitLineToNodes()
        {
            int intiNodeListcount = this.nodeList.Count;

            Node[] nodes = new Node[this.Count];

            for (int i = 0; i < this.Count; i++)
                nodes[i] = this[i] ;

            Array.Sort<IPoint>(nodes, this);

            INodeLine[] lines = new INodeLine[this.Count - 1];

            for (int i = 0; i < this.Count - 1; i++)
            {
                if (nodes[i] != nodes[i + 1])
                {
                    lines[i] = new NodeLine(nodes[i], nodes[i + 1]);
                }

                System.Diagnostics.Debug.Assert(lines[i].Length() != 0, "Zero length Line Split");
            }

            System.Diagnostics.Debug.Assert(nodeList.Count == intiNodeListcount, "Collection Changed , Should Not ");
            return lines;
        }

        private void SortNodes()
        {
           
        }

        #  region " Constructors And Factories "
        public static NodeLine Create(IPoint point1, IPoint point2)
        {
         //   if (point1 is Point && point2 is Point)
         //   { return new NodeLine(point1 as Point , point2 as Point); }
            
            if (point1 is Node && point2 is Node)
            { return new NodeLine(point1 as Node, point2 as Node); }
          /*  if (point1 is Node && point2 is GridPoint)
            { return new NodeLine(point1 as Node, point2 as GridPoint); }
            if (point1 is GridPoint && point2 is Node)
            { return new NodeLine(point1 as GridPoint, point2 as Node); }
            if (point1 is GridPoint && point2 is GridPoint)
            { return new NodeLine(point1 as GridPoint, point2 as GridPoint); }*/
            return new NodeLine(Node.CreateNode(point1), Node.CreateNode(point2));
            return new NodeLine();
        }

       // public NodeLine(GridPoint Point1, GridPoint point2) : base((Node)Point1, (Node)point2) { }
        public NodeLine(Node node1, Node node2) : base(node1, node2) { }
     //   public NodeLine(Node node1, GridPoint point2) : base(node1, (Node)point2) { }
      //  public NodeLine(GridPoint point1, Node node2) : base((Node)point1, node2) { }

       // public NodeLine(Point point1, Point point2) : base(point1, point2) { }

        public NodeLine() { }

        #endregion

        # region " INodeContainer implementation "

        public override IPoint SNode
        {
            get
            {
                return base.SNode;
            }
            set
            {
                base.SNode = value;
            }
        }
        public override IPoint ENode
        {
            get
            {
                return base.ENode;
            }
            set
            {
                base.ENode = value;
            }
        }

        public IEnumerator GetEnumerator()
        {
            yield return SNode;
            foreach (Node node in NodeList)
                yield return node;
            yield return ENode;
        }

        public bool Add(Node point)
        {

            if (SNode == null)
            { 
                SNode = point;throw new DomainModelExeption("Should not set Snode form here");
               // return true;  
            }
            if (ENode == null)
            { 
                ENode = point;
                throw new DomainModelExeption("Should not set Snode form here");
              //  return true;
            }
            else
            {
                if (this.Contains(point))
                    return false;
                else
                {
                    ILine line = new Line(sNode, eNode);
                    if (line.ContainsPointOpen(point))
                    {
                        AssertContainment(point);
                        AddSorted(point);

                        return true;
                    }
                    else return false;
                }
            }
        }

        private void AddSorted(Node point)
        {
         //   Array.Sort<IPoint>(NodeList, this);

            NodeList.Add(point);
        }

        private void AssertContainment(Node point)
        {
            /*
            foreach (Node node in this)
                System.Diagnostics.Debug.Assert(node.X != point.X || node.Y != point.Y || node.Z != point.Z, "              Already Exists a Node with That Coords In Line ");
             * */

        }

        public bool Remove(Node point)
        {
            if (NodeList.Contains(point))
            {
                int i = NodeList.IndexOf(point);
                NodeList.RemoveAt(i);
                return true;
            }
            if ((Point)point == (Point)SNode)
            {
                throw new DomainModelExeption("Should not Remove Snode form here");
                if (NodeList.Count != 0)
                { SNode = NodeList[0]; }
                else
                { return false; }
            }

            if ((Point)point ==(Point ) ENode)
            {
                throw new DomainModelExeption("Should not Remove Enode form here");
                if (NodeList.Count != 0)
                { ENode = NodeList[NodeList.Count]; }
                else
                { return false; }
            }
            return false;
        }

        public bool Contains(Node point)
        {
            foreach (Node node in this)
                if (node.X == point.X && node.Y == point.Y && node.Z == point.Z)
                    return true;
            return false;
        }

        public int Count
        {
            get
            {
                return NodeList.Count + 2;
            }
           
        }

        public Node this[int i]
        {

            get
            {
                if (i < -1) return null;
                if (i == 0) return SNode as Node;
                if (i == this.Count -1) return ENode as Node;
                if (i > 0) return NodeList[i - 1];
                return null;
            }

            set
            {
                if (i < -1) return;
                if (i == 0) sNode = value;
                if (i == Count -1) ENode = value ;
                if (i > 0 && i<Count -1 && !NodeList .Contains (value ))  NodeList[i - 1] = value;// dont use that to set intermediate nodes .

            }
        }
        #endregion

        # region " IModifiable implementation "
        public bool Move(Vector vector)
        {
            (SNode as Node).Move(vector);
            (ENode as Node).Move(vector);

            if (NodeList.Count > 0)
                foreach (Node node in NodeList)
                    node.Move(vector);
            return true;
        }
        public bool Move(double dx, double dy, double dz)
        {
            throw new NotImplementedException(""); 
        }

        #endregion

        # region "Casting Implementation "
     /*   public static implicit operator NodeLine(GridLine grideline)
        {
            return NodeLine.Create(grideline.SNode as Point , grideline.ENode as Point );
        }
      */
        #endregion

        #region INodeLine Members


        public INodeLine[] SplitLine(int number)
        {
            nodeList.Clear();
            double lenth = this.Length()/number ;
            double currentdist =0 ;
            IPoint newpoint ;
            for (int i = 0; i < number-1; i++)
            {
                currentdist = currentdist+lenth ;
                newpoint = GetPointToDistance(currentdist/this.Length ());
               this.Add(Node.CreateNode(newpoint ));

            }
            return SplitLineToNodes();
        }

        #endregion

    }
}
